#include "StdAfx.h"
#include "playLed.h"
#include "stdint.h"
#include "resource.h"
#include "playDlg.h"
#include "common.h"
#include "WinUser.h"
#include <math.h>

struct play_t
{
	char *name;
	HWND hwnd;
};

void playThread(void *arg);

playLed::playLed(HWND hwnd)
{
	m_hwnd = hwnd;
	m_portion = 0;
	m_radius = 0;
	m_dlg = 0;
	m_stoped = false;
}


playLed::~playLed(void)
{
	if (m_file.m_hFile != CFile::hFileNull)
		m_file.Close();
}

void playLed::destroy()
{
	if (m_file.m_hFile != CFile::hFileNull)
		m_file.Close();
}

void playLed::end()
{
	m_stoped = true;

	while(!m_exited);
}

bool playLed::begin(CString name)
{
	if(!m_file.Open(name.GetBuffer(0), CFile::modeRead, NULL))
		return false;

	char buf[1024];

	m_file.Read(buf, 32);
	if(memcmp(buf, "led!", 4)){
		m_file.Close();
		return false;
	}

	struct file_head *head = (struct file_head *)(buf+4);
	m_portion = head->portion;
	m_radius = head->radius;
	m_leaf = head->leaf;

	if(!m_image.IsNull())
		m_image.Destroy();

	m_image.Create(2*m_radius+1, 2*m_radius+1, 32);
	m_exited = false;
	return true;
}

void playLed::drawLine(CImage *image, double angle, unsigned size, unsigned char *pcolor)
{
	POINT center = {m_radius, m_radius};
	unsigned radius = m_image.GetHeight() / 2;

	double s_y = sin(angle);
	double s_x = cos(angle);

	for(int i = m_radius-1; i >= (int)(m_radius - size); i--){
		unsigned offset = 3*((m_radius-1)-i);

		BYTE r = (BYTE)pcolor[offset+2];
		BYTE g = (BYTE)pcolor[offset+1];
		BYTE b = (BYTE)pcolor[offset];

		image->SetPixelRGB(m_radius + i*s_x, m_radius + i*s_y, (BYTE)pcolor[offset+2], (BYTE)pcolor[offset+1], (BYTE)pcolor[offset]); 
	}
}

int playLed::play()
{
	unsigned char buf[10240];
	struct led_head head;
	uint32_t time = -1;
	bool isfirst = true;
	
	int seek = m_file.GetPosition();
	CImage *image = new CImage();
	image->Create(2*m_radius+1, 2*m_radius+1, 32);

	while(true){
		seek = m_file.GetPosition();
		int err = m_file.Read(&head, sizeof(head));
		if(err != sizeof(head)){
			if(0 > err){
				delete image;
				return -1;
			}

			::PostMessage(m_hwnd, WM_DRAWIMAGE, 0, (LPARAM)image);
			return -1;
		}

		if(head.magic != LED_MAGIC){
			assert(false);
			delete image;
			return -1;
		}

		if(head.len > sizeof(buf)){
			assert(false);
			delete image;
			return -1;
		}

		if(m_file.Read(buf, head.len) != head.len){
			assert(false);
			delete image;
			return -1;
		}

		if(head.type == LED_TYPE_PIC){
			if(isfirst){
				time = *(uint32_t*)buf;
				isfirst = false;
				continue;
			}else{
				LONGLONG seek = sizeof(head)+head.len;
				m_file.Seek(-seek, CFile::current);
				break;
			}
			
		}

		if(head.type != LED_TYPE_LINE)
			continue;

		seek = m_file.GetPosition();
		struct line_head *line = (struct line_head *)buf;
		uint16_t point = *(uint16_t*)buf;
		unsigned size = (head.len-(sizeof(struct line_head) - sizeof(struct led_head)))/3;
		double argle = (2 * PI * point)/(m_portion*m_leaf);

		drawLine(image, argle, size, buf+(sizeof(struct line_head) - sizeof(struct led_head)));
	}

	//m_dlg->drawImage(&m_image);
	::PostMessage(m_hwnd, WM_DRAWIMAGE, 0, (LPARAM)image);
	return time;
}

void playThread(void *arg)
{
	struct play_t *play = (struct play_t *)arg;
	CString file(play->name);
	HWND hwnd = play->hwnd;
	free(arg);

	playLed led(hwnd);
	if(!led.begin(file)){
		led.exit();
		return;
	}

	while(1){
		if(led.stoped())
			break;

		long now = GetTickCount();
		long time = led.play();
		if(0 > time)
			break;

		long current = GetTickCount();

		if(current >= now + time)
			continue;

		while(1){
			current = GetTickCount();
			if(current >= now + time)
				break;

			long timeSleep = now + time - current;
			
			if(led.stoped()){
				led.exit();
				return;
			}

			if(timeSleep > 100)
				timeSleep = 100;
				
			Sleep(timeSleep);
		}
	}

	led.exit();
}

int playLedImage(CString file, HWND hwnd)
{
	struct play_t *play =  (struct play_t *)malloc(sizeof(struct play_t) + file.GetLength() + 1);
	if(!play)
		return -1;

	play->name = (char*)(play+1);
	strcpy(play->name, file.GetBuffer(0));
	play->hwnd = hwnd;
	char *str = strdup(file.GetBuffer(0));


	_beginthread(playThread, 0, play);
	return 0;
}